package com.yanqu.road.server.manager.user;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.player.CrossUserBaseInfo;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.logic.bussiness.player.CrossUserBaseInfoBusiness;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.redis.RedisManger;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.manager.npc.CrossNpcUserMgr;
import com.yanqu.road.server.manger.IUserBaseInfoSyncListener;
import com.yanqu.road.utils.string.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class CrossUserMgr extends TempMgr {

    /**
     * k:UserId
     */
    private static Map<Long, CrossUserBaseInfo> userBaseInfoMap;

    /**
     * k:serverId  k: userAliasId   userAliasId对应的 CrossUserBaseInfo
     */
    private static Map<Long, Map<Long, CrossUserBaseInfo>> userAliasIdUserBaseInfoMap = new ConcurrentHashMap<>();

    private static Set<Long> selectDbUserIdList = new HashSet<>();

    public static List<CrossUserBaseInfo> getCrossUserBaseInfoList() {
        return new ArrayList<>(userBaseInfoMap.values());
    }

    public static void updateUserBaseInfo(long userId, UserBaseInfo userBaseInfo) {
        if (userBaseInfo == null) {
            return;
        }
        CrossUserBaseInfo info = userBaseInfoMap.get(userId);
        if (info == null) {
            info = userBaseInfoMap.get(userId);
            if (info == null) {
                info = new CrossUserBaseInfo();
                info.setUserId(userId);
                info.setLastUpdateTime(System.currentTimeMillis());
                info.setUserBaseInfo(userBaseInfo);
                info.setInsertOption();
                userBaseInfoMap.put(userId, info);
                Map<Long, CrossUserBaseInfo> map = getUserAliasIdUserBaseInfoMap(userBaseInfo.getServerId(), true);
                map.put(userBaseInfo.getUserAliasId(), info);
            }
        } else {
            info.setUserBaseInfo(userBaseInfo);
            info.setLastUpdateTime(System.currentTimeMillis());
        }
    }

    //加个是否被修改的标志，要实时更新的,目前就判断一下外观
    public static boolean updateUserBaseInfoChange(long userId, UserBaseInfo userBaseInfo) {
        if (userBaseInfo == null) {
            return false;
        }

        CrossUserBaseInfo info = getCrossUserBaseInfo(userId);
        if (info == null) {
            info = userBaseInfoMap.get(userId);
            if (info == null) {
                info = new CrossUserBaseInfo();
                info.setUserId(userId);
                info.setLastUpdateTime(System.currentTimeMillis());
                info.setUserBaseInfo(userBaseInfo);
                info.setInsertOption();
                userBaseInfoMap.put(userId, info);
                Map<Long, CrossUserBaseInfo> map = getUserAliasIdUserBaseInfoMap(userBaseInfo.getServerId(), true);
                map.put(userBaseInfo.getUserAliasId(), info);
            }
            return true;
        } else {
            boolean change = false;
            if (!info.getUserBaseInfo().getDecoration().equals(userBaseInfo.getDecoration())
                    || !info.getUserBaseInfo().getNickName().equals(userBaseInfo.getNickName())
            ) {
                change = true;
            }
            info.setUserBaseInfo(userBaseInfo);
            info.setLastUpdateTime(System.currentTimeMillis());
            return change;
        }

    }

    public static CrossUserBaseInfo getCrossUserBaseInfo(long userId) {
        CrossUserBaseInfo crossUserBaseInfo = null;
        crossUserBaseInfo = userBaseInfoMap.get(userId);
        if(ChannelConfig.USER_INFO_USE_REDIS == 1) {
            if (null == crossUserBaseInfo) {
                try {
                    String userObjStr = RedisManger.getRedisUtil().get("user_base_info:" + userId);
                    if (!StringUtils.isNullOrEmpty(userObjStr)) {
                        UserBaseInfo userBaseInfo = JSON.parseObject(userObjStr, UserBaseInfo.class);
                        crossUserBaseInfo = new CrossUserBaseInfo();
                        crossUserBaseInfo.setUserId(userId);
                        crossUserBaseInfo.setUserBaseInfo(userBaseInfo);
                        crossUserBaseInfo.setLastUpdateTime(System.currentTimeMillis());
                    }
                } catch (Exception e) {

                }
            }
        }
        if(null == crossUserBaseInfo) {
            crossUserBaseInfo = userBaseInfoMap.get(userId);
            if (crossUserBaseInfo == null) {
                synchronized (userBaseInfoMap) {
                    crossUserBaseInfo = userBaseInfoMap.get(userId);
                    if (crossUserBaseInfo == null && !selectDbUserIdList.contains(userId)) {
                        crossUserBaseInfo = CrossUserBaseInfoBusiness.getUserBaseInfoByUserId(userId);
                        if (crossUserBaseInfo != null) {
                            crossUserBaseInfo.setLastUpdateTime(System.currentTimeMillis());
                            userBaseInfoMap.put(userId, crossUserBaseInfo);
                            UserBaseInfo userBaseInfo = crossUserBaseInfo.getUserBaseInfo();
                            Map<Long, CrossUserBaseInfo> map = getUserAliasIdUserBaseInfoMap(userBaseInfo.getServerId(), true);
                            map.put(userBaseInfo.getUserAliasId(), crossUserBaseInfo);
                        }
                        selectDbUserIdList.add(userId);
                    }
                }
            }
        }
        return crossUserBaseInfo;
    }

    public static UserBaseInfo getUserBaseInfo(long relationshipUserId) {
        CrossUserBaseInfo crossUserBaseInfo = getCrossUserBaseInfo(relationshipUserId);
        if (crossUserBaseInfo == null) {
            // 压测测试，用户信息拿不到 拿一下npc的信息，对实际功能不影响
            crossUserBaseInfo = CrossNpcUserMgr.getCrossNpcUserBaseInfo(relationshipUserId);
            if (crossUserBaseInfo == null) {
                return null;
            }
        }
        return crossUserBaseInfo.getUserBaseInfo();
    }

    /**
     * 通过玩家id  获取区服id
     *
     * @param userId
     * @return
     */
    public static long getServerIdByUserId(long userId) {
        CrossUserBaseInfo crossUserBaseInfo = getCrossUserBaseInfo(userId);
        if (crossUserBaseInfo != null) {
            return crossUserBaseInfo.getUserBaseInfo().getServerId();
        }
        return 0;
    }

    // 赶时间乱写的，没事别用这个
    @Deprecated
    public static CrossUserBaseInfo getMemUserBaseInfo(long userId) {
        return userBaseInfoMap.get(userId);
    }


    /**
     * 获取玩家名称
     *
     * @param userId
     * @return
     */
    public static String getUserName(long userId) {
        CrossUserBaseInfo userBaseInfo = getCrossUserBaseInfo(userId);
        if (userBaseInfo == null) {
            return "";
        }
        return userBaseInfo.getUserBaseInfo().getNickName();
    }

    @Override
    public boolean reloadData() throws Exception {
        Map<Long, CrossUserBaseInfo> tempMap = new ConcurrentHashMap<>();
//        Map<Long, CrossUserBaseInfo> allUserBaseInfo = CrossUserBaseInfoBusiness.getAllUserBaseInfo();
        long startTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L);
        Map<Long, CrossUserBaseInfo> allUserBaseInfo = CrossUserBaseInfoBusiness.getUserBaseInfoUpdateInTime(startTime);
        tempMap.putAll(allUserBaseInfo);
        userBaseInfoMap = tempMap;
        for (CrossUserBaseInfo item : allUserBaseInfo.values()) {
            Map<Long, CrossUserBaseInfo> map = getUserAliasIdUserBaseInfoMap(item.getUserBaseInfo().getServerId(), true);
            map.put(item.getUserBaseInfo().getUserAliasId(), item);
        }

        return true;
    }

    public static Map<Long, CrossUserBaseInfo> getUserAliasIdUserBaseInfoMap(long serverId, boolean newIfNull) {
        Map<Long, CrossUserBaseInfo> map = userAliasIdUserBaseInfoMap.get(serverId);
        if (map == null && newIfNull) {
            map = new ConcurrentHashMap<>();
            userAliasIdUserBaseInfoMap.put(serverId, map);
        }
        return map;
    }

    public static long getCrossUserBaseInfoModiftyTime(long userId) {
        long modifyTime = 0;
        CrossUserBaseInfo crossUserBaseInfo = getCrossUserBaseInfo(userId);
        if (null != crossUserBaseInfo) {
            modifyTime = crossUserBaseInfo.getLastUpdateTime();
        }
        return modifyTime;
    }

    @Override
    public boolean save() {
        removeOverTimeData();
        for (CrossUserBaseInfo baseInfo : new ArrayList<>(userBaseInfoMap.values())) {
            if (baseInfo.isDirty()) {
                CrossUserBaseInfoBusiness.update(baseInfo);
            }
        }
        return true;
    }

    private void removeOverTimeData() {
        long startTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L);
        List<CrossUserBaseInfo> needRemoveUserList = new ArrayList<>();
        for (CrossUserBaseInfo crossUserBaseInfo : userBaseInfoMap.values()) {
            if (crossUserBaseInfo.getLastUpdateTime() < startTime) {
                needRemoveUserList.add(crossUserBaseInfo);
            }
            if (needRemoveUserList.size() > 300000) {
                break;
            }
        }

        if (needRemoveUserList.size() > 0) {
            getLogger().debug("remove user info {}", needRemoveUserList.size());
            for (CrossUserBaseInfo userBaseInfo : needRemoveUserList) {
                synchronized (userBaseInfoMap) {
                    Map<Long, CrossUserBaseInfo> serverUserBaseInfoMap = userAliasIdUserBaseInfoMap.get(userBaseInfo.getUserBaseInfo().getServerId());
                    if (serverUserBaseInfoMap != null) {
                        serverUserBaseInfoMap.remove(userBaseInfo.getUserBaseInfo().getUserAliasId());
                    }
                    userBaseInfoMap.remove(userBaseInfo.getUserId());
                    selectDbUserIdList.remove(userBaseInfo.getUserId());
                }
            }
        }
    }

    @Override
    public boolean init() throws Exception {
        reload();
        CrossUserNotifyMgr.addSyncListener(new SyncHandle());
        return true;
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }


    public class SyncHandle implements IUserBaseInfoSyncListener {
        @Override
        public void notifySync(UserBaseInfo userBaseInfo, long userId) {
            updateUserBaseInfo(userId, userBaseInfo);
        }
    }

}
